package com.msxt.websocket;

import com.alibaba.fastjson.JSON;
import com.msxt.dto.ChatMessage;
import com.msxt.dto.YonghuEntity;
import com.msxt.service.ChatMessageService;
import com.msxt.service.YonghuService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Component
@ServerEndpoint("/ws/{consultBianhao}/{userId}")
public class WebSocketServer implements ApplicationContextAware {

    private static ApplicationContext applicationContext;
    private static ChatMessageService chatService;
    private static YonghuService yonghuService;
    private static final ExecutorService executor = Executors.newCachedThreadPool();

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        WebSocketServer.applicationContext = applicationContext;
        WebSocketServer.chatService = applicationContext.getBean(ChatMessageService.class);
        WebSocketServer.yonghuService = applicationContext.getBean(YonghuService.class);
    }

    private static Map<String, CopyOnWriteArraySet<Session>> consultSessions = new ConcurrentHashMap<>();
    private static Map<String, SessionInfo> sessionInfoMap = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(Session session,
                       @PathParam("consultBianhao") String consultBianhao,
                       @PathParam("userId") String userId) {
        System.out.println("客户端连接建立 - 咨询编号: " + consultBianhao + ", 用户ID: " + userId);

        SessionInfo sessionInfo = new SessionInfo(consultBianhao, userId);
        sessionInfoMap.put(session.getId(), sessionInfo);

        CopyOnWriteArraySet<Session> sessions = consultSessions.computeIfAbsent(consultBianhao, k -> new CopyOnWriteArraySet<>());
        sessions.add(session);
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        executor.submit(() -> {
            try {
                SessionInfo sessionInfo = sessionInfoMap.get(session.getId());
                if (sessionInfo == null) {
                    return;
                }

                ChatMessage chatMessage = JSON.parseObject(message, ChatMessage.class);
                chatMessage.setConsultBianhao(sessionInfo.getConsultBianhao());
                chatMessage.setSenderId(sessionInfo.getUserId());

                String realUserName = getSenderName(sessionInfo.getUserId());
                chatMessage.setSenderName(realUserName);

                chatMessage.setTimestamp(System.currentTimeMillis());

                if (chatMessage.getId() == null) {
                    chatMessage.setId(System.currentTimeMillis() + (long)(Math.random() * 1000000));
                }

                if ("heartbeat".equals(chatMessage.getMessageType())) {
                    ChatMessage heartbeatResponse = new ChatMessage();
                    heartbeatResponse.setMessageType("heartbeat_ack");
                    heartbeatResponse.setContent("心跳响应");
                    heartbeatResponse.setConsultBianhao(chatMessage.getConsultBianhao());
                    heartbeatResponse.setTimestamp(System.currentTimeMillis());
                    heartbeatResponse.setSenderId("system");
                    heartbeatResponse.setSenderName("系统");

                    sendToConsult(chatMessage.getConsultBianhao(), JSON.toJSONString(heartbeatResponse));
                    return;
                }

                if (chatService != null) {
                    // 关键修复：确保咨询记录存在
                    if (StringUtils.isNotBlank(chatMessage.getConsultBianhao())) {
                        chatService.saveMessage(chatMessage);
                    }
                }

                sendToConsult(sessionInfo.getConsultBianhao(), JSON.toJSONString(chatMessage));
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    private String getSenderName(String userId) {
        try {
            YonghuEntity user = yonghuService.getById(userId);
            if (user != null && user.getYonghuxingming() != null) {
                return user.getYonghuxingming();
            }
        } catch (Exception e) {
        }
        return "用户" + userId;
    }

    @OnClose
    public void onClose(Session session) {
        SessionInfo sessionInfo = sessionInfoMap.get(session.getId());
        if (sessionInfo != null) {
            String consultBianhao = sessionInfo.getConsultBianhao();
            String userId = sessionInfo.getUserId();

            CopyOnWriteArraySet<Session> sessions = consultSessions.get(consultBianhao);
            if (sessions != null) {
                sessions.remove(session);
                if (sessions.isEmpty()) {
                    consultSessions.remove(consultBianhao);
                }
            }

            sessionInfoMap.remove(session.getId());
            System.out.println("客户端连接关闭 - 咨询编号: " + consultBianhao + ", 用户ID: " + userId);

            sendLeaveMessage(consultBianhao, userId);
        }
    }

    private void sendLeaveMessage(String consultBianhao, String userId) {
        try {
            ChatMessage leaveMessage = new ChatMessage("system", "用户 " + userId + " 离开对话", consultBianhao);
            leaveMessage.setTimestamp(System.currentTimeMillis());
            String messageJson = JSON.toJSONString(leaveMessage);
            sendToConsult(consultBianhao, messageJson);
        } catch (Exception e) {
        }
    }

    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    public void sendToConsult(String consultBianhao, String message) {
        CopyOnWriteArraySet<Session> sessions = consultSessions.get(consultBianhao);
        if (sessions != null) {
            for (Session session : sessions) {
                try {
                    if (session.isOpen()) {
                        session.getBasicRemote().sendText(message);
                    }
                } catch (IOException e) {
                    sessions.remove(session);
                    sessionInfoMap.remove(session.getId());
                }
            }
        }
    }

    public void sendToAllClient(String message) {
        for (CopyOnWriteArraySet<Session> sessions : consultSessions.values()) {
            for (Session session : sessions) {
                try {
                    if (session.isOpen()) {
                        session.getBasicRemote().sendText(message);
                    }
                } catch (IOException e) {
                }
            }
        }
    }

    public void sendToUser(String consultBianhao, String userId, String message) {
        CopyOnWriteArraySet<Session> sessions = consultSessions.get(consultBianhao);
        if (sessions != null) {
            for (Session session : sessions) {
                SessionInfo sessionInfo = sessionInfoMap.get(session.getId());
                if (sessionInfo != null && sessionInfo.getUserId().equals(userId)) {
                    try {
                        if (session.isOpen()) {
                            session.getBasicRemote().sendText(message);
                        }
                    } catch (IOException e) {
                    }
                }
            }
        }
    }

    public int getOnlineUserCount(String consultBianhao) {
        CopyOnWriteArraySet<Session> sessions = consultSessions.get(consultBianhao);
        return sessions != null ? sessions.size() : 0;
    }

    private static class SessionInfo {
        private String consultBianhao;
        private String userId;

        public SessionInfo(String consultBianhao, String userId) {
            this.consultBianhao = consultBianhao;
            this.userId = userId;
        }

        public String getConsultBianhao() { return consultBianhao; }
        public String getUserId() { return userId; }
    }
}